﻿using System;
using System.Collections.Generic;
using System.Threading;
using log4net;

namespace ActionLogic
{
    /// <summary>
    /// Action executor state.
    /// </summary>
    public enum ActionExecutorState
    {
        Start,
        Pause,
        Stop
    }

    /// <summary>
    /// Describes implementation of action executor.
    /// </summary>
    public class ActionExecutor : IActionExecutor
    {
        #region Fields

        //private static readonly ILog logger = LogManager.GetLogger(typeof (ActionExecutor));

        private static readonly ActionExecutor _instance = new ActionExecutor();

        private readonly List<PriorityAction> _actionQueue;

        #endregion

        #region Properties

        public ActionExecutorState ActionExecutorState { get; private set; }

        public Thread UpdateThread { get; set; }

        public static EventWaitHandle Ready = new AutoResetEvent(false);
        public static EventWaitHandle Go = new AutoResetEvent(false);

        #endregion

        #region Constructor

        private ActionExecutor()
        {
            _actionQueue = new List<PriorityAction>();
            ActionExecutorState = ActionExecutorState.Stop;
        }

        #endregion

        #region Methods

        public static IActionExecutor GetInstance()
        {
            return _instance;
        }

        #region Lifecycle

        public void Start()
        {
            ActionExecutorState = ActionExecutorState.Start;
            StartExecutingProcess();
        }

        private void StartExecutingProcess()
        {
            while (ActionExecutorState == ActionExecutorState.Start)
            {
                lock (this)
                {
                    if (IsStateNotStartOrEmptyQueue()) continue;
                    var maxPriorityAction = GetMaxPriorityAction();
                    Execute(maxPriorityAction);
                    _actionQueue.Remove(maxPriorityAction);
                }
            }
        }

        private bool IsStateNotStartOrEmptyQueue()
        {
            return ActionExecutorState != ActionExecutorState.Start || IsEmpty();
        }

        private PriorityAction GetMaxPriorityAction()
        {
            _actionQueue.Sort();
            return _actionQueue[0];
        }

        public void Execute(PriorityAction action)
        {
            if (action.IsBackground)
            {
                ExecuteInBackground(action);
            }
            else
            {
                action.Execute();
            }
        }

        private void ExecuteInBackground(PriorityAction action)
        {
            //if (UpdateThread == null || !UpdateThread.IsAlive)
            //{
            //    UpdateThread = new Thread(context => action.Execute());
            //    UpdateThread.Start();
            //}
            action.Execute();
        }

        public void Pause()
        {
            ActionExecutorState = ActionExecutorState.Pause;
        }

        public void Stop()
        {
            ActionExecutorState = ActionExecutorState.Stop;

            lock (this)
            {
                _actionQueue.Clear();
            }
        }

        #endregion

        public void Add(PriorityAction priorityAction)
        {
            _actionQueue.Add(priorityAction);
        }

        public bool IsEmpty()
        {
            return _actionQueue.Count == 0;
        }

        #endregion
    }
}
